﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SharpBolt.BasicIntefaces;
using SharpBolt.Basics;

namespace SharpBolt.Input
{
    public class InputObserver
    {
        IInputProvider provider;

        public delegate void KeyEvent(string keyname);

        public class Key
        {
            public string name;
            public bool isDown;
            public enum KeyState { Up, Pressed, Down, Released }
            public KeyState State;

            public EventHandler Pressed;
            public EventHandler Released;

            public Key(string name)
            {
                this.name = name;
                this.isDown = false;
                State = KeyState.Up;
            }
        }

        public List<Key> KnownKeys;

        public Key FindKey(string keyname)
        {
            return KnownKeys.Find(p => p.name == keyname);
        }

        public Key GetKey(string keyname)
        {
            Key key = KnownKeys.Find(p => p.name == keyname);

            if (key == null)
            {
               throw new ArgumentException("unknown key:" + keyname);
            }

            return key;
        }

        public bool IsKeyDown(string keyname)
        {
            return GetKey(keyname).isDown;
        }

        public bool IsKeyPressed(string keyname)
        {
            return GetKey(keyname).State == Key.KeyState.Pressed;
        }

        public bool IsKeyReleased(string keyname)
        {
            return GetKey(keyname).State == Key.KeyState.Released;
        }

        public SbManipulator FindManipulator(string manipulatorName)
        {
            if (!Manipulators.ContainsKey(manipulatorName)) return null;
            return Manipulators[manipulatorName];
        }

        public Dictionary<string, SbManipulator> Manipulators;

        void KeyPressedEvent(string keyname)
        {
            Key key = CheckKey(keyname);

            if (key.Pressed != null) key.Pressed(key,EventArgs.Empty);
            key.isDown = true;
        }
        
        void KeyReleasedEvent(string keyname)
        {
            Key key = CheckKey(keyname);

            if (key.Released != null) key.Released(key, EventArgs.Empty);
            key.isDown = false;
        }

        private Key CheckKey(string keyname)
        {
            Key key = KnownKeys.Find(p => p.name == keyname);

            if (key == null)
            {
                key = new Key(keyname);
                KnownKeys.Add(key);
            }
            return key;
        }        

        public void UpdateKeysState()
        {
            foreach (var key in KnownKeys)
            {    
                if(key.isDown)
                switch (key.State)
                {
                    case Key.KeyState.Released:
                        key.State = Key.KeyState.Up;
                        break;

                    case Key.KeyState.Up:
                        key.State = Key.KeyState.Pressed;
                        break;

                    case Key.KeyState.Pressed:
                        key.State = Key.KeyState.Down;
                        break;
                }

                if (!key.isDown)
                    switch (key.State)
                    {
                        case Key.KeyState.Pressed:
                            key.State = Key.KeyState.Down;
                            break;

                        case Key.KeyState.Down:
                            key.State = Key.KeyState.Released;
                            break;

                        case Key.KeyState.Released:
                            key.State = Key.KeyState.Up;
                            break;
                    }
            }
        }

        public void UpdateManipulators()
        {
            Manipulators = provider.GetManipulators();
        }

        public InputObserver() {
            Manipulators = new Dictionary<string, SbManipulator>();
            KnownKeys = new List<Key>();
        }

        public SbManipulator Pointer
        {
            get { return FindManipulator("default"); }
            private set { }
        }

        public void AttachInputProvider(IInputProvider provider){
            provider.KeyDown += this.KeyPressedEvent;
            provider.KeyUp += this.KeyReleasedEvent;

            string[] keynames = provider.GetKnownKeys();
            foreach (var keyname in keynames)
            {
                Key key = CheckKey(keyname);
            }

            this.provider = provider;
        }
    }
}
